package cn.iocoder.yudao.framework.websocket.config;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.websocket.core.handler.CustomSubProtocolWebSocketHandler;
import cn.iocoder.yudao.framework.websocket.core.interceptor.WebSocketChannelInterceptor;
import cn.iocoder.yudao.framework.websocket.core.interceptor.WebSocketHandshakeInterceptor;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.support.AbstractSubscribableChannel;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

@AutoConfiguration
@EnableWebSocket
@EnableWebSocketMessageBroker
@EnableConfigurationProperties(WebSocketProperties.class)
public class WebSocketConfiguration extends WebSocketMessageBrokerConfigurationSupport  implements WebSocketMessageBrokerConfigurer {
    private final WebSocketProperties webSocketProperties;

    private final OAuth2TokenApi oauth2TokenApi;
    private final SecurityProperties securityProperties;

    WebSocketConfiguration(WebSocketProperties webSocketProperties, OAuth2TokenApi oauth2TokenApi,SecurityProperties securityProperties){
        this.webSocketProperties = webSocketProperties;
        this.oauth2TokenApi = oauth2TokenApi;
        this.securityProperties = securityProperties;
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {

        String appEndPoint =  StrUtil.addPrefixIfNot(webSocketProperties.getAppEndPoint(),"/");
       // List<String> brokers = webSocketProperties.getBrokers();
        List<String> brokers = webSocketProperties.getBrokers().stream()
                .map(s -> StrUtil.addPrefixIfNot(s,"/"))
                .collect(Collectors.toList());
        String[] brokersArray = ArrayUtil.toArray(brokers, String.class);
        if(webSocketProperties.isRelayEnable()){
            registry.enableStompBrokerRelay(brokersArray).setRelayHost(webSocketProperties.getRelayHost()).setRelayPort(webSocketProperties.getRelayPort())
                    .setClientLogin(webSocketProperties.getClientLogin()).setClientPasscode(webSocketProperties.getClientPassword())
                    .setSystemLogin(webSocketProperties.getClientLogin()).setSystemPasscode(webSocketProperties.getClientPassword());
        }else{
            registry.enableSimpleBroker(brokersArray);
        }
        registry.setApplicationDestinationPrefixes(appEndPoint);
        registry.setUserDestinationPrefix(StrUtil.addPrefixIfNot(webSocketProperties.getUserEndPoint(),"/"));
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        String endPoint =  StrUtil.addPrefixIfNot(webSocketProperties.getEndPoint(),"/");
        registry.addEndpoint(endPoint).setAllowedOriginPatterns("*").addInterceptors(new WebSocketHandshakeInterceptor());
    }
    /**
     * 配置发送与接收的消息参数，可以指定消息字节大小，缓存大小，发送超时时间
     *
     */
    @Override
    public void configureWebSocketTransport( WebSocketTransportRegistration registration) {
        /*
         * 1. setMessageSizeLimit 设置消息缓存的字节数大小 字节
         * 2. setSendBufferSizeLimit 设置websocket会话时，缓存的大小 字节
         * 3. setSendTimeLimit 设置消息发送会话超时时间，毫秒
         */
        registration.setMessageSizeLimit(10240)
                .setSendBufferSizeLimit(10240)
                .setSendTimeLimit(100000);
    }
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new WebSocketChannelInterceptor(oauth2TokenApi,securityProperties,webSocketProperties));
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        super.configureClientOutboundChannel(registration);
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        super.addArgumentResolvers(argumentResolvers);
    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        super.addReturnValueHandlers(returnValueHandlers);
    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        return super.configureMessageConverters(messageConverters);
    }
    @Override
    @Bean
    public WebSocketHandler subProtocolWebSocketHandler(AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel) {
        return new CustomSubProtocolWebSocketHandler(clientInboundChannel, clientOutboundChannel, webSocketProperties);
    }
}
